package com.bytz.modules.cms.auditBatch.service.direct;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bytz.common.constant.CommonConstant;
import com.bytz.common.exception.BytzBootException;
import com.bytz.common.system.query.QueryGenerator;
import com.bytz.common.util.mentity.EntityMergeInfoV2;
import com.bytz.common.util.mentity.util.MergeEntityOptions;
import com.bytz.common.util.mentity.util.MergeEntityUtil;
import com.bytz.modules.cms.auditBatch.service.IAdminResellerProductChangeService;
import com.bytz.modules.cms.product.entity.Product;
import com.bytz.modules.cms.product.service.IAdminProductService;
import com.bytz.modules.cms.reseller.constant.ResellerConstant;
import com.bytz.modules.cms.reseller.entity.ResellerProduct;
import com.bytz.modules.cms.reseller.entity.ResellerProductChange;
import com.bytz.modules.cms.reseller.mapper.ResellerProductChangeMapper;
import com.bytz.modules.cms.reseller.service.IResellerProductService;
import com.bytz.modules.cms.user.constants.AuditBatchConstants;
import com.bytz.modules.cms.user.service.IAuditBatchService;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class AdminResellerProductChangeServiceImpl extends ServiceImpl<ResellerProductChangeMapper, ResellerProductChange> implements IAdminResellerProductChangeService {

    @Autowired
    private IResellerProductService resellerProductService;

    @Autowired
    private IAuditBatchService auditBatchService;

    @Autowired
    private IAdminProductService productService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncChangeByBatchId(String batchId) {

        List<ResellerProductChange> list = getByBatchId(batchId);

        if (CollectionUtil.isEmpty(list)) {
            return;
        }

        Map<String, List<ResellerProductChange>> idGroup = list.stream()
                .collect(Collectors.groupingBy(ResellerProductChange::getResellerProductId));

        List<ResellerProduct> updateList = idGroup.keySet().stream().map(id -> {
            ResellerProduct updateEntity = new ResellerProduct();
            updateEntity.setId(id);
            idGroup.get(id).stream().findFirst().ifPresent(change -> {

                updateEntity.setOffsetType(change.getOffsetType());
                updateEntity.setOffsetValue(change.getOffsetValue());
                updateEntity.setEffectTime(LocalDateTime.now());
            });
            return updateEntity;
        }).collect(Collectors.toList());

        updateSyncData(batchId, updateList);
    }

    /**
     * 根据batchId获取未同步的change
     */
    private List<ResellerProductChange> getByBatchId(String batchId) {

        // 填入主表id
        MPJLambdaWrapper<ResellerProductChange> wrapper = new MPJLambdaWrapper<>();
        List<ResellerProductChange> result = baseMapper.selectJoinList(ResellerProductChange.class, wrapper
                .selectAll(ResellerProductChange.class)
                .selectAs(ResellerProduct::getId, ResellerProductChange::getResellerProductId)
                .leftJoin(ResellerProduct.class, on -> on
                        .eq(ResellerProductChange::getResellerId, ResellerProduct::getResellerId)
                        .eq(ResellerProductChange::getProductId, ResellerProduct::getProductId)
                        .eq(ResellerProduct::getDelFlag, CommonConstant.DEL_FLAG_0)
                )
                .eq(ResellerProductChange::getAuditBatchId, batchId)
                .eq(ResellerProductChange::getSyncStatus, AuditBatchConstants.SyncStatus.WAITING_SYNC)
                .orderByDesc(ResellerProductChange::getCreateTime)
        );

        List<ResellerProduct> insertList = result.stream()
                .filter(change -> change.getResellerProductId() == null)
                .map(change -> {
                    // 如果主表中没有分类等级都对应的记录，添加一条
                    ResellerProduct insert = new ResellerProduct();
                    insert.setResellerId(change.getResellerId());
                    insert.setProductId(change.getProductId());
                    insert.setProductNumber(change.getProductNumber());
                    insert.setOffsetType(ResellerConstant.ResellerProductOffsetType.ADD);
                    insert.setOffsetValue(BigDecimal.ZERO);
                    insert.setEffectTime(LocalDateTime.now());
                    return insert;
                }).collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(insertList)) {

            resellerProductService.saveBatch(insertList);

            Map<String, String> insertMap = insertList.stream()
                    .collect(Collectors.toMap(t -> t.getResellerId() + t.getProductId(), ResellerProduct::getId));

            result.forEach(change -> {
                String id = insertMap.get(change.getResellerId() + change.getProductId());
                if (id != null) {
                    change.setResellerProductId(id);
                }
            });
        }

        updateBatchById(result);

        return result;
    }

    /**
     * 更改auditBatch表 将对应id设置为已同步
     * 更改change表 对应batchId设置为已同步
     * 更新对应的主表
     */
    private void updateSyncData(String batchId, List<ResellerProduct> updateList) {

        resellerProductService.updateBatchById(updateList);

        lambdaUpdate()
                .in(ResellerProductChange::getAuditBatchId, batchId)
                .set(ResellerProductChange::getSyncStatus, AuditBatchConstants.SyncStatus.SYNCED)
                .update();

        auditBatchService.setStatusSynced(batchId);
    }

    @Override
    public IPage<ResellerProductChange> queryPage(Page<ResellerProductChange> page, ResellerProductChange change, Map<String, String[]> parameterMap) {
        QueryWrapper<ResellerProductChange> queryWrapper = QueryGenerator.initQueryWrapper(change, parameterMap);
        return page(page, queryWrapper);
    }

    @Override
    public void importExcel(String batchId, String resellerId, List<ResellerProductChange> list) {

        List<String> repeatList = list.stream()
                .collect(Collectors.groupingBy(ResellerProductChange::getProductNumber, Collectors.counting()))
                .entrySet().stream().filter(e -> e.getValue() > 1)
                .map(Map.Entry::getKey).collect(Collectors.toList());

        if (repeatList.size() > 0) {
            throw new BytzBootException(repeatList + "变更记录导入数据有重复");
        }
        //取出ProductNumber
        List<String> numList =
                list.stream()
                        .map(ResellerProductChange::getProductNumber)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());

        //判断numList是否为null或者empty
        if (CollectionUtils.isEmpty(numList)) {
            throw new BytzBootException("表格商品编号未填写");
        }
        //查询number对应实体类
        List<Product> productList =
                productService.lambdaQuery().in(Product::getProductNumber, numList).list();
        //判断传入的个数与查询到的个数是否匹配
        if (productList.size() != numList.size()) {
            //获取db productNumber
            List<String> dbProductNumberList =
                    productList.stream().map(Product::getProductNumber).collect(Collectors.toList());
            String productNumberStr =
                    numList.stream()
                            .filter(num -> !dbProductNumberList.contains(num))
                            .collect(Collectors.joining(","));
            throw new BytzBootException("表格商品编号" + productNumberStr + "不存在");
        }
        //将list转map，键为ProductNumber
        Map<String, Product> productMap =
                productList.stream()
                        .collect(Collectors.toMap(Product::getProductNumber, product -> product));
        list.forEach(t -> {
            Product product = productMap.get(t.getProductNumber());
            t.setProductId(product.getId());
            t.setProductDesc(product.getMaterialDesc());
            t.setBasePrice(product.getBasePrice());
            t.setAuditBatchId(batchId);
            t.setResellerId(resellerId);
        });

        EntityMergeInfoV2<ResellerProductChange> mergeInfo = MergeEntityUtil.calculateEntityMergeInfo(list, getByBatchId(batchId), MergeEntityOptions.<ResellerProductChange>builder().build());
        MergeEntityUtil.doDbMerge(mergeInfo, this);
    }

    @Override
    public boolean checkChangeData(String id) {
        return false;
    }

    @Override
    public void updateEffectTimeByBatchId(String id, LocalDateTime effectTime) {
        lambdaUpdate()
                .eq(ResellerProductChange::getAuditBatchId, id)
                .set(ResellerProductChange::getEffectTime, effectTime)
                .update();
    }

    /**
     * 验证优惠申请是否存在，再保存
     */
    @Override
    public Boolean saveChange(ResellerProductChange change) {
        boolean exists = lambdaQuery().eq(ResellerProductChange::getAuditBatchId, change.getAuditBatchId())
                .eq(ResellerProductChange::getProductNumber, change.getProductNumber())
                .eq(ResellerProductChange::getResellerId, change.getResellerId())
                .exists();
        if (exists) {
            throw new BytzBootException("经销商独享优惠申请已经存在");
        }
        return save(change);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeByBatchId(String id) {
        lambdaUpdate().eq(ResellerProductChange::getAuditBatchId, id).remove();
    }
}